﻿Public Module MWackyParcer

    Private Structure STokenInfoPre
        Public Pos As Int32
        Public Rank As Int32
    End Structure

    Public Function Execute(ByVal objParcerTree_i As NSTZWackyParcer.ITokenParcerTreeNode, ByVal strRawText_i As String) _
    As CTokenBase
        Dim objParcerPrn As ITokenParcerTreeNode = objParcerTree_i
        Dim numPosCurr As Int32 = 0
        Dim numPosMax As Int32 = strRawText_i.Length - 1
        Dim numRankLB As Int32 = Int32.MinValue

        objParcerPrn.BegParce(strRawText_i, numPosCurr, numRankLB)

        Dim objDesignerPrn As CTokenDesignerBase = objParcerPrn.TokenFactory.NewDesigner(strRawText_i, numPosCurr)
        Dim objParcerEnum As NSCllG.IEnumerable(Of ITokenParcerTreeNode)
        Dim blnParcerMustOccure As Boolean

        If objParcerPrn.ChildEnum Is Nothing Then
            Throw New XWackyParcerTreeInvalid("Invalid parce tree. Root token parcer has no childs.")
        Else
            objParcerEnum = objParcerPrn.ChildEnum
            blnParcerMustOccure = objParcerPrn.MustOccureChild
        End If

        Dim objParcerPrnStack As New NSCllG.Stack(Of ITokenParcerTreeNode)
        Dim objDesignerPrnStack As New NSCllG.Stack(Of CTokenDesignerBase)
        Dim blnMainStop As Boolean = False
        Dim objTokenChl As CTokenBase

        Do
            Dim udsPreParceInfoBest = New STokenInfoPre _
                With {.Rank = numRankLB, .Pos = 0}
            Dim objParcerChlBest As ITokenParcerTreeNode = Nothing

            If numPosCurr <= numPosMax Then
                For Each objParcerIt As ITokenParcerTreeNode In objParcerEnum
                    Dim udsPreParceInfo = New STokenInfoPre With {.Pos = numPosCurr, .Rank = numRankLB}

                    objParcerIt.BegParce(strRawText_i, udsPreParceInfo.Pos, udsPreParceInfo.Rank)

                    If udsPreParceInfoBest.Rank < udsPreParceInfo.Rank Then
                        objParcerChlBest = objParcerIt
                        udsPreParceInfoBest = udsPreParceInfo
                    ElseIf udsPreParceInfo.Rank <> numRankLB AndAlso udsPreParceInfoBest.Rank = udsPreParceInfo.Rank Then
                        Throw New XWackyParceError("Ambiguity found.", numPosCurr)
                    End If
                Next
            End If

            If objParcerChlBest Is Nothing Then
                If blnParcerMustOccure Then
                    Throw New XWackyParceError("Unexected char.", numPosCurr)
                End If

                If objParcerPrnStack.Count = 0 Then
                    blnMainStop = True
                    Exit Do
                Else
                    If objParcerPrn.ParcerType = ETokenParcerType.Delimeter Then
                        objParcerPrn.EndParce(strRawText_i, numPosCurr, Nothing)
                    Else
                        objTokenChl = Nothing
                        objParcerPrn.EndParce(strRawText_i, numPosCurr, objTokenChl)

                        objTokenChl = objDesignerPrn.Assemble(objTokenChl)
                        objDesignerPrn = objDesignerPrnStack.Pop()
                        objDesignerPrn.PartAdd(objTokenChl)
                    End If

                    objParcerEnum = objParcerPrn.NextEnum
                    blnParcerMustOccure = objParcerPrn.MustOccureNext

                    objParcerPrn = objParcerPrnStack.Pop()
                End If

                Do While objParcerEnum Is Nothing
                    If blnParcerMustOccure Then
                        Throw New XWackyParcerTreeInvalid("Invalid parce tree. The collection of next parcers can not be empty when item is required.")
                    End If

                    If objParcerPrnStack.Count = 0 Then
                        blnMainStop = True
                        Exit Do
                    Else
                        If objParcerPrn.ParcerType = ETokenParcerType.Delimeter Then
                            objParcerPrn.EndParce(strRawText_i, numPosCurr, Nothing)
                        Else
                            objTokenChl = Nothing
                            objParcerPrn.EndParce(strRawText_i, numPosCurr, objTokenChl)

                            objTokenChl = objDesignerPrn.Assemble(objTokenChl)
                            objDesignerPrn = objDesignerPrnStack.Pop()
                            objDesignerPrn.PartAdd(objTokenChl)
                        End If

                        objParcerEnum = objParcerPrn.NextEnum
                        blnParcerMustOccure = objParcerPrn.MustOccureNext

                        objParcerPrn = objParcerPrnStack.Pop()
                    End If
                Loop
            Else ' Not objParcerChlBest Is Nothing
                numPosCurr = udsPreParceInfoBest.Pos

                If objParcerChlBest.ParcerType = ETokenParcerType.WhiteSpace Then
                    objParcerChlBest.EndParce(strRawText_i, numPosCurr, Nothing)
                Else
                    If objParcerChlBest.ChildEnum Is Nothing Then
                        If objParcerChlBest.ParcerType = ETokenParcerType.Delimeter Then
                            objParcerChlBest.EndParce(strRawText_i, numPosCurr, Nothing)
                        Else
                            objTokenChl = Nothing
                            objParcerChlBest.EndParce(strRawText_i, numPosCurr, objTokenChl)
                            objDesignerPrn.PartAdd(objTokenChl)
                        End If

                        objParcerEnum = objParcerChlBest.NextEnum
                        blnParcerMustOccure = objParcerChlBest.MustOccureNext

                        Do While objParcerEnum Is Nothing
                            If blnParcerMustOccure Then
                                Throw New XWackyParcerTreeInvalid("Invalid parce tree. The collection of next parcers can not be empty when item is required.")
                            End If

                            If objParcerPrnStack.Count = 0 Then
                                blnMainStop = True
                                Exit Do
                            Else
                                If objParcerPrn.ParcerType = ETokenParcerType.Delimeter Then
                                    objParcerPrn.EndParce(strRawText_i, numPosCurr, Nothing)
                                Else
                                    objTokenChl = Nothing
                                    objParcerPrn.EndParce(strRawText_i, numPosCurr, objTokenChl)

                                    objTokenChl = objDesignerPrn.Assemble(objTokenChl)
                                    objDesignerPrn = objDesignerPrnStack.Pop()
                                    objDesignerPrn.PartAdd(objTokenChl)
                                End If

                                objParcerEnum = objParcerPrn.NextEnum
                                blnParcerMustOccure = objParcerPrn.MustOccureNext

                                objParcerPrn = objParcerPrnStack.Pop()
                            End If
                        Loop
                    Else 'Not objParcerBest.ChildEnum Is Nothing 
                        objParcerPrnStack.Push(objParcerPrn)
                        objParcerPrn = objParcerChlBest

                        If objParcerPrn.ParcerType <> ETokenParcerType.Delimeter Then
                            objDesignerPrnStack.Push(objDesignerPrn)
                            objDesignerPrn = objParcerPrn.TokenFactory.NewDesigner(strRawText_i, numPosCurr)
                        End If

                        objParcerEnum = objParcerPrn.ChildEnum
                        blnParcerMustOccure = objParcerPrn.MustOccureChild
                    End If
                End If
            End If
        Loop Until blnMainStop

        objTokenChl = Nothing
        objParcerPrn.EndParce(strRawText_i, numPosCurr, objTokenChl)

        Return objDesignerPrn.Assemble(objTokenChl)
    End Function

End Module
